home *** CD-ROM | disk | FTP | other *** search
/ Amiga Format CD 52 / Amiga Format AFCD52 (Issue 136, May 2000).iso / -serious- / hardware / ahd12 / ahd / ahd.s next >
Text File  |  2000-02-28  |  36KB  |  1,178 lines

  1. MYDEVNAME       MACRO
  2.                 DC.B    'ahd.device',0
  3.                 ENDM
  4.  
  5. FASTBOOT        equ     1      ;If defined ahd will not reset controller
  6.                                 ;at boottime
  7.  
  8.         SECTION section
  9.  
  10.         NOLIST
  11.         include "exec/types.i"
  12.         include "exec/nodes.i"
  13.         include "exec/lists.i"
  14.         include "exec/libraries.i"
  15.         include "exec/devices.i"
  16.         include "exec/io.i"
  17.         include "exec/alerts.i"
  18.         include "exec/initializers.i"
  19.         include "exec/memory.i"
  20.         include "exec/resident.i"
  21.         include "exec/ables.i"
  22.         include "exec/errors.i"
  23.         include "exec/tasks.i"
  24.         include "libraries/expansionbase.i"
  25.         include "libraries/expansion.i"
  26.         include "libraries/configvars.i"
  27.         include "libraries/configregs.i"
  28.         include "libraries/romboot_base.i"
  29.  
  30.         include "asmsupp.i"
  31.         include "messages.i"
  32.  
  33.         include "mydev.i"
  34.  
  35.         xdef    myName
  36.         xdef    subSysName
  37.         XREF    _AbsExecBase
  38.  
  39. ;
  40. ; Imports from assembly module hdif.asm
  41. ;
  42.  
  43.         XREF    Read
  44.         XREF    Write
  45.         XREF    FormatTrk
  46.         XREF    doreset
  47.         XREF    doinit
  48.         XREF    doseek
  49.         XREF    readsec
  50.         XREF    doerror
  51.         XREF    putchar
  52.         XREF    puthex
  53.         XREF    hdconfig
  54.         XREF    _inbuffer
  55.  
  56. ;
  57. ; Imports from C module auto.c
  58. ;
  59.  
  60.         XREF    _config
  61.  
  62. ;
  63. ; Imports from assembly module cdeb.asm
  64. ;
  65.  
  66.         XREF    _SysBase
  67.  
  68. ;
  69. ; Imports for this module
  70. ;
  71.  
  72.         XLIB    AddDevice
  73.         XLIB    Enqueue
  74.         XLIB    AddIntServer
  75.         XLIB    RemIntServer
  76.         XLIB    Debug
  77.         XLIB    InitStruct
  78.         XLIB    MakeLibrary
  79.         XLIB    OpenLibrary
  80.         XLIB    CloseLibrary
  81.         XLIB    Alert
  82.         XLIB    FreeMem
  83.         XLIB    Remove
  84.         XLIB    AllocMem
  85.         XLIB    AddTask
  86.         XLIB    PutMsg
  87.         XLIB    RemTask
  88.         XLIB    ReplyMsg
  89.         XLIB    Signal
  90.         XLIB    GetMsg
  91.         XLIB    Wait
  92.         XLIB    WaitPort
  93.         XLIB    AllocSignal
  94.         XLIB    SetTaskPri
  95.         XLIB    GetCurrentBinding       ; Get list of boards for this driver
  96.         XLIB    MakeDosNode
  97.         XLIB    AddDosNode
  98.  
  99.         INT_ABLES
  100.  
  101.  
  102.         ; The first executable location.  This should return an error
  103.         ; in case someone tried to run you as a program (instead of
  104.         ; loading you as a library).
  105. FirstAddress:
  106.         CLEAR   d0
  107.         rts
  108.  
  109. ;-----------------------------------------------------------------------
  110. ; A romtag structure.  Both "exec" and "ramlib" look for
  111. ; this structure to discover magic constants about you
  112. ; (such as where to start running you from...).
  113. ;-----------------------------------------------------------------------
  114.  
  115.         ; Most people will not need a priority and should leave it at zero.
  116.         ; the RT_PRI field is used for configuring the roms.  Use "mods" from
  117.         ; wack to look at the other romtags in the system
  118. MYPRI   EQU     20
  119.  
  120. initDDescrip:
  121.                                         ;STRUCTURE RT,0
  122.           DC.W    RTC_MATCHWORD         ; UWORD RT_MATCHWORD
  123.           DC.L    initDDescrip          ; APTR  RT_MATCHTAG
  124.           DC.L    EndCode               ; APTR  RT_ENDSKIP
  125.           dc.b    RTF_AUTOINIT
  126.           DC.B    VERSION               ; UBYTE RT_VERSION
  127.           DC.B    NT_DEVICE             ; UBYTE RT_TYPE
  128.           DC.B    MYPRI                 ; BYTE  RT_PRI
  129.           DC.L    myName                ; APTR  RT_NAME
  130.           DC.L    idString              ; APTR  RT_IDSTRING
  131.           DC.L    Init                  ; APTR  RT_INIT
  132.                                         ; LABEL RT_SIZE
  133.  
  134.  
  135.         ; this is the name that the device will have
  136. _myName:          ; For C
  137. subSysName:
  138. myName:         MYDEVNAME
  139.  
  140.         ; a major version number.
  141. VERSION:        EQU     1
  142.  
  143.         ; A particular revision.  This should uniquely identify the bits in the
  144.         ; device.  I use a script that advances the revision number each time
  145.         ; I recompile.  That way there is never a question of which device
  146.         ; that really is.
  147. REVISION:       EQU     2
  148.  
  149.         ; this is an identifier tag to help in supporting the device
  150.         ; format is 'name version.revision (dd MON yyyy)',<cr>,<lf>,<null>
  151. idString:       dc.b    'ahd.device 1.2 (10 Oct 1988)',13,10,0
  152.  
  153.         ; force word allignment
  154.  
  155.         cnop    0,4
  156.  
  157.         ; The romtag specified that we were "RTF_AUTOINIT".  This means
  158.         ; that the RT_INIT structure member points to one of these
  159.         ; tables below.  If the AUTOINIT bit was not set then RT_INIT
  160.         ; would point to a routine to run.
  161.  
  162. Init:
  163.         DC.L    MyDev_Sizeof            ; data space size
  164.         DC.L    funcTable               ; pointer to function initializers
  165.         DC.L    dataTable               ; pointer to data initializers
  166.         DC.L    initRoutine             ; routine to run
  167.  
  168.  
  169. funcTable:
  170.  
  171.         ;------ standard system routines
  172.         dc.l    Open
  173.         dc.l    Close
  174.         dc.l    Expunge
  175.         dc.l    Null
  176.  
  177.         ;------ my device definitions
  178.         dc.l    BeginIO
  179.         dc.l    AbortIO
  180.  
  181.         ;------ function table end marker
  182.         dc.l    -1
  183.  
  184.  
  185.         ; The data table initializes static data structures.
  186.         ; The format is specified in exec/InitStruct routine's
  187.         ; manual pages.  The INITBYTE/INITWORD/INITLONG routines
  188.         ; are in the file "exec/initializers.i".  The first argument
  189.         ; is the offset from the device base for this byte/word/long.
  190.         ; The second argument is the value to put in that cell.
  191.         ; The table is null terminated
  192. dataTable:
  193.         INITBYTE        LH_TYPE,NT_DEVICE
  194.         INITLONG        LN_NAME,myName
  195.         INITBYTE        LIB_FLAGS,LIBF_SUMUSED!LIBF_CHANGED
  196.         INITWORD        LIB_VERSION,VERSION
  197.         INITWORD        LIB_REVISION,REVISION
  198.         INITLONG        LIB_IDSTRING,idString
  199.         DC.L    0
  200.  
  201.  
  202.         ; This routine gets called after the device has been allocated.
  203.         ; The device pointer is in D0.  The segment list is in a0.
  204.         ; If it returns non-zero then the device will be linked into
  205.         ; the device list.
  206. initRoutine:
  207.  
  208. ; Register Usage
  209. ; ==============
  210. ; a3 -- Points to tempory RAM
  211. ; a4 -- Expansion library base
  212. ; a5 -- device pointer
  213. ; a6 -- Exec base
  214. ;
  215. ;----------------------------------------------------------------------
  216.         ;------ get the device pointer into a convenient A register
  217.         PUTMSG  80,<'--- %s/Init: called'>
  218.         movem.l d1-d7/a0-a5,-(sp)       ; Preserve ALL modified registers
  219.         move.l  d0,a5
  220.  
  221.         ;------ save a pointer to exec
  222.         move.l  a6,md_SysLib(a5)
  223.         move.l  a6,_SysBase
  224.  
  225.         ;------ save a pointer to our loaded code
  226.         move.l  a0,md_SegList(a5)
  227.  
  228.         ; You would normally set d0 to a NULL if your initialization failed,
  229.         ; but I'm not doing that for this demo, since it is unlikely
  230.         ; you actually have a board with this particular manufacturer ID
  231.         ; installed when running this demo.
  232.         ;
  233.  
  234.         DMPNL   10
  235.         moveq   #0,d3           ; Default device is drive 0
  236.  
  237.         ifd     FASTBOOT
  238.  
  239.         lea     _inbuffer,a2    ; Try to read sec 0 off of that drive
  240.         move.l  #0,d0
  241.         move.l  #512,d1
  242.         bsr     readsec
  243.         beq.s   awake           ; If controller already awake - yahoo
  244.  
  245.         endc
  246.  
  247.         bsr     doreset         ; Reset the drive if hung
  248.         bne     ir_int
  249.  
  250.         lea     _inbuffer,a2    ; Try to read sec 0 off of that drive
  251.         move.l  #0,d0
  252.         move.l  #512,d1
  253.         bsr     readsec
  254.         bne.s   noparms         ; If sec 0 gives error - boot with default
  255.  
  256. awake:
  257.         PUTMSG  5,<'Reading config data'>
  258.         lea     _inbuffer,a0
  259.         bsr     hdconfig        ; Set parms as read
  260. noparms:
  261.         bsr     doinit          ; Send drive parms
  262.         bne.s   ir_int
  263.  
  264.         bsr     _config
  265.  
  266.         PUTMSG  80,<'%s/Init: succeeded'>
  267.         move.l  a5,d0
  268.         movem.l (sp)+,d1-d7/a0-a5
  269.         rts
  270. ir_int:
  271.         PUTMSG  80,<'%s/Init: failed'>
  272.         move.l  #0,d0
  273.         movem.l (sp)+,d1-d7/a0-a5
  274.         rts
  275.  
  276. ;----------------------------------------------------------------------
  277. ;
  278. ; here begins the system interface commands.  When the user calls
  279. ; OpenLibrary/CloseLibrary/RemoveLibrary, this eventually gets translated
  280. ; into a call to the following routines (Open/Close/Expunge).  Exec
  281. ; has already put our device pointer in a6 for us.  Exec has turned
  282. ; off task switching while in these routines (via Forbid/Permit), so
  283. ; we should not take too long in them.
  284. ;
  285. ;----------------------------------------------------------------------
  286.  
  287.  
  288.         ; Open sets the IO_ERROR field on an error.  If it was successfull,
  289.         ; we should set up the IO_UNIT field.
  290.  
  291. Open:           ; ( device:a6, iob:a1, unitnum:d0, flags:d1 )
  292.         PUTMSG  80,<'%s/Open: called'>
  293.         movem.l d2/a2/a3/a5,-(sp)
  294.  
  295.         move.l  a1,a2           ; save the iob
  296.  
  297.         ;------ see if the unit number is in range
  298.         subq    #1,d0           ; Unit ZERO isn't allowed
  299.         cmp.l   #MD_NUMUNITS,d0
  300.         bcc.s   Open_Error      ; unit number out of range
  301.  
  302.         ;------ see if the unit is already initialized
  303.         move.l  d0,d2           ; save unit number
  304.         lsl.l   #2,d0
  305.         lea.l   md_Units(a6,d0.l),a5
  306.         move.l  (a5),d0
  307.         bne.s   Open_UnitOK
  308.  
  309.         ;------ try and conjure up a unit
  310.         bsr     InitUnit
  311.  
  312.         ;------ see if it initialized OK
  313.         move.l  (a5),d0
  314.         beq.s   Open_Error
  315.  
  316. Open_UnitOK:
  317.         move.l  d0,a3           ; unit pointer in a3
  318.  
  319.         move.l  d0,IO_UNIT(a2)
  320.  
  321.         ;------ mark us as having another opener
  322.         addq.w  #1,LIB_OPENCNT(a6)
  323.         addq.w  #1,UNIT_OPENCNT(a3)
  324.  
  325.         ;------ prevent delayed expunges
  326.         bclr    #LIBB_DELEXP,md_Flags(a6)
  327.         moveq.l #0,d0
  328.  
  329. Open_End:
  330.  
  331.         movem.l (sp)+,d2/a2/a3/a5
  332.         PUTMSG  80,<'Open - End'>
  333.         rts
  334.  
  335. Open_Error:
  336.         move.b  #IOERR_OPENFAIL,IO_ERROR(a2)
  337.         move.b  #IOERR_OPENFAIL,d0
  338.         bra.s   Open_End
  339.  
  340.         ; There are two different things that might be returned from
  341.         ; the Close routine.  If the device is no longer open and
  342.         ; there is a delayed expunge then Close should return the
  343.         ; segment list (as given to Init).  Otherwise close should
  344.         ; return NULL.
  345.  
  346. Close:          ; ( device:a6, iob:a1 )
  347.         movem.l d1/a2-a3,-(sp)
  348.         PUTMSG  80,<'%s/Close: called'>
  349.  
  350.         move.l  a1,a2
  351.  
  352.         move.l  IO_UNIT(a2),a3
  353.  
  354.         ;------ make sure the iob is not used again
  355.         moveq.l #-1,d0
  356.         move.l  d0,IO_UNIT(a2)
  357.         move.l  d0,IO_DEVICE(a2)
  358.  
  359.         ;------ see if the unit is still in use
  360.         subq.w  #1,UNIT_OPENCNT(a3)
  361.  
  362. ;        bne.s   Close_Device
  363. ;        bsr     ExpungeUnit
  364.  
  365. Close_Device:
  366.         ;------ mark us as having one fewer openers
  367.         moveq.l #0,d0
  368.         subq.w  #1,LIB_OPENCNT(a6)
  369.  
  370.         ;------ see if there is anyone left with us open
  371.         bne.s   Close_End
  372.  
  373.         ;------ see if we have a delayed expunge pending
  374.         btst    #LIBB_DELEXP,md_Flags(a6)
  375.         beq.s   Close_End
  376.  
  377.         ;------ do the expunge
  378.         bsr     Expunge
  379.  
  380. Close_End:
  381.         movem.l (sp)+,d1/a2-a3
  382.         rts
  383.  
  384.  
  385.         ; There are two different things that might be returned from
  386.         ; the Expunge routine.  If the device is no longer open
  387.         ; then Expunge should return the segment list (as given to
  388.         ; Init).  Otherwise Expunge should set the delayed expunge
  389.         ; flag and return NULL.
  390.         ;
  391.         ; One other important note: because Expunge is called from
  392.         ; the memory allocator, it may NEVER Wait() or otherwise
  393.         ; take long time to complete.
  394.  
  395. Expunge:        ; ( device: a6 )
  396.         PUTMSG  80,<'%s/Expunge: called'>
  397.  
  398.         movem.l d1/d2/a5/a6,-(sp)       ; Best to save ALL modified registers
  399.         move.l  a6,a5
  400.         move.l  md_SysLib(a5),a6
  401.  
  402.         ;------ see if anyone has us open
  403.         tst.w   LIB_OPENCNT(a5)
  404. ;        beq     1$
  405.  
  406.         ;------ it is still open.  set the delayed expunge flag
  407.         bset    #LIBB_DELEXP,md_Flags(a5)
  408.         CLEAR   d0
  409.         bra.s   Expunge_End
  410.  
  411. 1$:
  412.         ;------ go ahead and get rid of us.  Store our seglist in d2
  413.         move.l  md_SegList(a5),d2
  414.  
  415.         ;------ unlink from device list
  416.         move.l  a5,a1
  417.         CALLSYS Remove
  418.  
  419.         ;
  420.         ; device specific closings here...
  421.         ;
  422.  
  423.         ;------ free our memory
  424.         CLEAR   d0
  425.         CLEAR   d1
  426.         move.l  a5,a1
  427.         move.w  LIB_NEGSIZE(a5),d1
  428.  
  429.         sub.w   d1,a1
  430.         add.w   LIB_POSSIZE(a5),d0
  431.         add.l   d1,d0
  432.  
  433.         CALLSYS FreeMem
  434.  
  435.         ;------ set up our return value
  436.         move.l  d2,d0
  437.  
  438. Expunge_End:
  439.         movem.l (sp)+,d1/d2/a5/a6
  440.         rts
  441.  
  442.  
  443. Null:
  444.         PUTMSG  30,<'%s/Null: called'>
  445.         CLEAR   d0
  446.         rts
  447.  
  448.  
  449. InitUnit:       ; ( d2:unit number, a3:scratch, a6:devptr )
  450.         PUTMSG  80,<'%s/InitUnit: called'>
  451.         movem.l d2-d4/a2/a4,-(sp)
  452.  
  453.         ;------ allocate unit memory
  454.         move.l  #MyDevUnit_Sizeof,d0
  455.         move.l  #MEMF_PUBLIC!MEMF_CLEAR,d1
  456.         LINKSYS AllocMem,md_SysLib(a6)
  457.  
  458.         tst.l   d0
  459.         beq     InitUnit_End
  460.  
  461.         PUTMSG  80,<'Allocated memory for Unit ok'>
  462.  
  463.         move.l  d0,a3
  464.         move.b  d2,mdu_UnitNum(a3)      ; initialize unit number
  465.         move.l  a6,mdu_Device(a3)       ; initialize device pointer
  466.  
  467.         tst.l   d2
  468.         bne.s   iu_Unit1
  469.         move.b  #0,mdu_UnitMask(a3)
  470.         bra.s   iu_Unit2
  471. iu_Unit1:
  472.         move.b  #$20,mdu_UnitMask(a3)
  473. iu_Unit2:
  474.  
  475.         tst.l   md_Process(a6)
  476.         bne     iu_NoProc
  477.  
  478.         ;------ start up the unit process.  We do a trick here --
  479.         ;------ we set his message port to PA_IGNORE until the
  480.         ;------ new process has a change to set it up.
  481.         ;------ We cannot go to sleep here: it would be very nasty
  482.         ;------ if someone else tried to open the unit
  483.         ;------ (exec's OpenDevice has done a Forbid() for us --
  484.         ;------ we depend on this to become single threaded).
  485.  
  486.         move.l  #MyProc_Sizeof,d0
  487.         move.l  #MEMF_PUBLIC!MEMF_CLEAR,d1
  488.         LINKSYS AllocMem,md_SysLib(a6)
  489.  
  490.         move.l  d0,a4
  491.         move.l  a4,md_Process(a6)
  492.  
  493.         ;------ Initialize the stack information
  494.         lea     mp_stack(a4),a0        ; Low end of stack
  495.         move.l  a0,mp_tcb+TC_SPLOWER(a4)
  496.         lea     MYPROCSTACKSIZE(a0),a0  ; High end of stack
  497.         move.l  a0,mp_tcb+TC_SPUPPER(a4)
  498.         move.l  a6,-(A0)                ; argument -- device ptr
  499.         move.l  a0,mp_tcb+TC_SPREG(a4)
  500.         ;------ initialize the unit's list
  501.         lea     MP_MSGLIST(a4),a0
  502.         NEWLIST a0
  503.         lea     mp_tcb(a4),a0
  504.         move.l  a0,MP_SIGTASK(a4)
  505.         moveq.l #0,d0                   ; Don't need to re-zero it
  506.         move.l  a4,a2                   ; InitStruct is initializing the UNIT
  507.         lea.l   mdu_Init,A1
  508.         LINKSYS InitStruct,md_SysLib(a6)
  509.  
  510.         move.l  a4,mp_is+IS_DATA(a4)   ; Pass int. server unit addr.
  511.  
  512. ;       Startup the task
  513.         lea     mp_tcb(a4),a1
  514.         lea     Proc_Begin(PC),a2
  515.         move.l  a4,-(sp)                ; Preserve UNIT pointer
  516.         lea     -1,a4                   ; generate address error
  517.                                         ; if task ever "returns"
  518.         CLEAR   d0
  519.         LINKSYS AddTask,md_SysLib(a6)
  520.         move.l  (sp)+,a4                ; restore UNIT pointer
  521.  
  522.         PUTMSG  80,<'AddTask done'>
  523.  
  524. iu_NoProc:
  525.         ;------ mark us as ready to go
  526.         move.l  d2,d0                   ; unit number
  527.         lsl.l   #2,d0
  528.         move.l  a3,md_Units(a6,d0.l)    ; set unit table
  529.  
  530.  
  531. InitUnit_End:
  532.         movem.l (sp)+,d2-d4/a2/a4
  533.         rts
  534.  
  535.         ;------ got an error.  free the unit structure that we allocated.
  536. InitUnit_FreeUnit:
  537.         bsr     FreeUnit
  538.         bra.s   InitUnit_End
  539.  
  540. FreeUnit:       ; ( a3:unitptr, a6:deviceptr )
  541.         move.l  a3,a1
  542.         move.l  #MyDevUnit_Sizeof,d0
  543.         LINKSYS FreeMem,md_SysLib(a6)
  544.         rts
  545.  
  546.  
  547. ExpungeUnit:    ; ( a3:unitptr, a6:deviceptr )
  548.         PUTMSG  80,<'%s/ExpungeUnit: called'>
  549.         move.l  d2,-(sp)
  550.  
  551.         move.l  md_Process(a6),a4
  552. ;
  553. ; If you can expunge you unit, and each unit has it's own interrups,
  554. ; you must remember to remove its interrupt server
  555. ;
  556.  
  557.         IFD     INTRRUPT
  558.         lea.l   mp_is(a4),a1           ; Point to interrupt structure
  559.         moveq   #3,d0                   ; Portia interrupt bit 3
  560.         LINKSYS RemIntServer,md_SysLib(a6) ;Now remove the interrupt server
  561.         ENDC
  562.  
  563.         ;------ get rid of the unit's task.  We know this is safe
  564.         ;------ because the unit has an open count of zero, so it
  565.         ;------ is 'guaranteed' not in use.
  566.         lea     mp_tcb(a4),a1
  567.         LINKSYS RemTask,md_SysLib(a6)
  568.  
  569.         ;------ save the unit number
  570.         CLEAR   d2
  571.         move.b  mdu_UnitNum(a3),d2
  572.  
  573.         ;------ free the unit structure.
  574.         bsr     FreeUnit
  575.  
  576.         ;------ clear out the unit vector in the device
  577.         lsl.l   #2,d2
  578.         clr.l   md_Units(a6,d2.l)
  579.  
  580.         move.l  (sp)+,d2
  581.  
  582.         rts
  583.  
  584. ;----------------------------------------------------------------------
  585. ;
  586. ; here begins the device specific functions
  587. ;
  588. ;----------------------------------------------------------------------
  589.  
  590. ; cmdtable is used to look up the address of a routine that will
  591. ; implement the device command.
  592. cmdtable:
  593.         DC.L    Invalid         ; $00000001
  594.         DC.L    MyReset         ; $00000002
  595.         DC.L    hdRead          ; $00000004     Common routine for read/write
  596.         DC.L    hdWrite         ; $00000008
  597.         DC.L    Update          ; $00000010
  598.         DC.L    Clear           ; $00000020
  599.         DC.L    MyStop          ; $00000040
  600.         DC.L    Start           ; $00000080
  601.         DC.L    Flush           ; $00000100
  602.         DC.L    Motor           ; $00000200  motor      (NO-OP)
  603.         DC.L    Seek            ; $00000400  seek       (NO-OP)
  604.         DC.L    hdFormat        ; $00000800  format -> WRITE for RAMDISK
  605.         DC.L    MyRemove        ; $00001000  remove             (NO-OP)
  606.         DC.L    ChangeNum       ; $00002000  changenum          (Returns 0)
  607.         DC.L    ChangeState     ; $00004000  changestate        (Returns 0)
  608.         DC.L    ProtStatus      ; $00008000  protstatus         (Returns 0)
  609.         DC.L    RawRead         ; Not supported (INVALID)
  610.         DC.L    RawWrite        ; Not supported (INVALID)
  611.         DC.L    GetDriveType    ; Get drive type        (Returns 1)
  612.         DC.L    GetNumTracks    ; Get number of tracks (Returns NUMTRKS)
  613.         DC.L    AddChangeInt    ; Add disk change interrupt (NO-OP)
  614.         DC.L    RemChangeInt    ; Remove disk change interrupt ( NO-OP)
  615.         dc.l    ReadConfig      ; Read config from io_Data
  616. cmdtable_end:
  617.  
  618. ; this define is used to tell which commands should not be queued
  619. ; command zero is bit zero.
  620. ; The immediate commands are Invalid, Reset, Stop, Start, Flush
  621. IMMEDIATES      EQU     $000001c3
  622.  
  623. ; These commands can NEVER be done "immediately" if using interrupts,
  624. ; since they would "wait" for the interrupt forever!
  625. ; Read, Write, Format
  626. NEVERIMMED      EQU     $0040080C
  627.  
  628. ; BeginIO starts all incoming io.  The IO is either queued up for the
  629. ; unit task or processed immediately.
  630. ;
  631.  
  632. BeginIO:        ; ( iob: a1, device:a6 )
  633.         PUTMSG  80,<'%s/BeginIO: called'>
  634.         movem.l d1/a0/a3/a4,-(sp)
  635.  
  636.         ;------ bookkeeping
  637.         move.l  IO_UNIT(a1),a3
  638.         move.l  md_Process(a6),a4
  639.  
  640.         ;------ see if the io command is within range
  641.         move.w  IO_COMMAND(a1),d0
  642.         cmp.w   #MYDEV_END,d0
  643.         bcc     BeginIO_NoCmd
  644.  
  645.         DISABLE a0
  646.  
  647.         ;------ process all immediate commands no matter what
  648.         move.l  #IMMEDIATES,d1
  649.         btst    d0,d1
  650.         bne.s   BeginIO_Immediate
  651.  
  652.         IFD     INTRRUPT        ; if using interrupts,
  653.         ;------ queue all NEVERIMMED commands no matter what
  654.         move.l  #NEVERIMMED,d1
  655.         btst    d0,d1
  656.         bne.s   BeginIO_QueueMsg
  657.         ENDC
  658.  
  659.         ;------ see if the unit is STOPPED.  If so, queue the msg.
  660.         btst    #MDUB_STOPPED,UNIT_FLAGS(a4)
  661.         bne.s   BeginIO_QueueMsg
  662.  
  663.         ;------ this is not an immediate command.  see if the device is
  664.         ;------ busy.
  665.         bset    #UNITB_ACTIVE,UNIT_FLAGS(a4)
  666.         beq.s   BeginIO_Immediate
  667.  
  668.         ;------ we need to queue the device.  mark us as needing
  669.         ;------ task attention.  Clear the quick flag
  670. BeginIO_QueueMsg:
  671.         BSET    #UNITB_INTASK,UNIT_FLAGS(a4)
  672.         bclr    #IOB_QUICK,IO_FLAGS(a1)
  673.  
  674.         ENABLE  a0
  675.  
  676.         move.l  a4,a0
  677.         LINKSYS PutMsg,md_SysLib(a6)
  678.         bra     BeginIO_End
  679.  
  680. BeginIO_Immediate:
  681.         ENABLE  a0
  682.  
  683.         bsr     PerformIO
  684.  
  685. BeginIO_End:
  686.         movem.l (sp)+,d1/a0/a3/a4
  687.         rts
  688.  
  689. BeginIO_NoCmd:
  690.         move.b  #IOERR_NOCMD,IO_ERROR(a1)
  691.         bra.s   BeginIO_End
  692.  
  693.  
  694. ;
  695. ; PerformIO actually dispatches an io request.  It expects a3 to already
  696. ; have the unit pointer in it.  a6 has the device pointer (as always).
  697. ; a1 has the io request.  Bounds checking has already been done on
  698. ; the io request.
  699. ;
  700.  
  701. PerformIO:      ; ( iob:a1, unitptr:a3, devptr:a6 )
  702.         PUTMSG  80,<'PerformIO: called'>
  703.         move.l  a2,-(sp)
  704.         move.l  a1,a2
  705.  
  706.         clr.b   IO_ERROR(A2)            ; No error so far
  707.         move.w  IO_COMMAND(a2),d0
  708.         lsl     #2,d0                   ; Multiply by 4 to get table offset
  709.         lea     cmdtable(pc),a0
  710.         move.l  0(a0,d0.w),a0
  711.  
  712.         jsr     (a0)
  713.  
  714.         move.l  (sp)+,a2
  715.         rts
  716.  
  717. ;
  718. ; TermIO sends the IO request back to the user.  It knows not to mark
  719. ; the device as inactive if this was an immediate request or if the
  720. ; request was started from the server task.
  721. ;
  722.  
  723. TermIO:         ; ( iob:a1, unitptr:a3, devptr:a6 )
  724.         PUTMSG  80,<'%s/TermIO: called'>
  725.         move.w  IO_COMMAND(a1),d0
  726.         move.w  #IMMEDIATES,d1
  727.         btst    d0,d1
  728.         bne.s   TermIO_Immediate
  729.  
  730.         ;------ we may need to turn the active bit off.
  731.         btst    #UNITB_INTASK,UNIT_FLAGS(a4)
  732.         bne.s   TermIO_Immediate
  733.  
  734.         ;------ the task does not have more work to do
  735.         bclr    #UNITB_ACTIVE,UNIT_FLAGS(a4)
  736.  
  737. TermIO_Immediate:
  738.         ;------ if the quick bit is still set then we don't need to reply
  739.         ;------ msg -- just return to the user.
  740.         btst    #IOB_QUICK,IO_FLAGS(a1)
  741.         bne.s   TermIO_End
  742.  
  743.         LINKSYS ReplyMsg,md_SysLib(a6)
  744.  
  745. TermIO_End:
  746.         rts
  747.  
  748.  
  749.         ; ( iob: a1, device:a6 )
  750. ;----------------------------------------------------------------------
  751. ;
  752. ; here begins the functions that implement the device commands
  753. ; all functions are called with:
  754. ;       a1 -- a pointer to the io request block
  755. ;       a2 -- another pointer to the iob
  756. ;       a3 -- a pointer to the unit
  757. ;       a6 -- a pointer to the device
  758. ;
  759. ; Commands that conflict with 68000 instructions have a "My" prepended
  760. ; to them.
  761. ;----------------------------------------------------------------------
  762. AbortIO:
  763. RawRead:                ; 10 Not supported      (INVALID)
  764. RawWrite:               ; 11 Not supported      (INVALID)
  765. Invalid:
  766.         move.b  #IOERR_NOCMD,IO_ERROR(a1)
  767.         bsr     TermIO
  768.         rts
  769.  
  770. MyReset:
  771. AddChangeInt:
  772. RemChangeInt:
  773. MyRemove:
  774. Seek:
  775. Motor:
  776. ChangeNum:
  777. ChangeState:
  778. ProtStatus:
  779.         clr.l   IO_ACTUAL(a1)   ; Indicate drive isn't protected
  780.         bsr     TermIO
  781.         rts
  782.  
  783. GetDriveType:
  784.         move.l  #1,IO_ACTUAL(a1)                ; Make it look like 3.5"
  785.         bsr     TermIO
  786.         rts
  787.  
  788. GetNumTracks:
  789.         move.l  #615,IO_ACTUAL(a1)     ; Number of 10 sector tracks
  790.         bsr     TermIO
  791.         rts
  792.  
  793. hdRead:
  794.         movem.l d0-d7/a0-a6,-(sp)
  795.         move.b  mdu_UnitMask(a3),d3
  796.         PUTMSG  30,<'hdRead: called'>
  797.         bsr     Read
  798.         movem.l (sp)+,d0-d7/a0-a6
  799.         bsr     TermIO
  800.         rts
  801. hdWrite:
  802.         movem.l d0-d7/a0-a6,-(sp)
  803.         move.b  mdu_UnitMask(a3),d3
  804.         PUTMSG  30,<'hdWrite: called'>
  805.         bsr     Write
  806.         movem.l (sp)+,d0-d7/a0-a6
  807.         bsr     TermIO
  808.         rts
  809. hdFormat:
  810.         movem.l d0-d7/a0-a6,-(sp)
  811.         PUTMSG  30,<'hdFormat: called'>
  812.         move.b  mdu_UnitMask(a3),d3
  813.         bsr     FormatTrk
  814.         movem.l (sp)+,d0-d7/a0-a6
  815.         bsr     TermIO
  816.         rts
  817.  
  818. ReadConfig:
  819.         movem.l d0-d7/a0-a6,-(sp)
  820.         PUTMSG  30,<'ReadConfig: called'>
  821.         move.l  IO_DATA(a1),a0
  822.         move.b  mdu_UnitMask(a3),d3
  823.         bsr     hdconfig
  824.         bsr     doreset
  825.         bsr     doinit
  826.         movem.l (sp)+,d0-d7/a0-a6
  827.         bsr     TermIO
  828.         rts
  829. ;
  830. ; Update and Clear are internal buffering commands.  Update forces all
  831. ; io out to its final resting spot, and does not return until this is
  832. ; done.  Clear invalidates all internal buffers.  Since this device
  833. ; has no internal buffers, these commands do not apply.
  834. ;
  835.  
  836. Update:
  837.         PUTMSG  80,<'%s/Update: called'>
  838.         bra     Invalid
  839. Clear:
  840.         PUTMSG  80,<'%s/Clear: called'>
  841.         bra     Invalid
  842.  
  843. ;
  844. ; the Stop command stop all future io requests from being
  845. ; processed until a Start command is received.  The Stop
  846. ; command is NOT stackable: e.g. no matter how many stops
  847. ; have been issued, it only takes one Start to restart
  848. ; processing.
  849. ;
  850.  
  851. MyStop:
  852.         PUTMSG  80,<'%s/MyStop: called'>
  853.         bset    #MDUB_STOPPED,UNIT_FLAGS(a4)
  854.  
  855.         bsr     TermIO
  856.         rts
  857.  
  858. Start:
  859.         PUTMSG  80,<'%s/Start: called'>
  860.         bsr     InternalStart
  861.  
  862.         move.l  a2,a1
  863.         bsr     TermIO
  864.  
  865.         rts
  866.  
  867. InternalStart:
  868.         ;------ turn processing back on
  869.         bclr    #MDUB_STOPPED,UNIT_FLAGS(a4)
  870.  
  871.         ;------ kick the task to start it moving
  872.         move.l  a4,a1
  873.         CLEAR   d0
  874.         move.l  MP_SIGBIT(a4),d1
  875.         bset    d1,d0
  876.         LINKSYS Signal,md_SysLib(a6)
  877.  
  878.         rts
  879.  
  880. ;
  881. ; Flush pulls all io requests off the queue and sends them back.
  882. ; We must be careful not to destroy work in progress, and also
  883. ; that we do not let some io requests slip by.
  884. ;
  885. ; Some funny magic goes on with the STOPPED bit in here.  Stop is
  886. ; defined as not being reentrant.  We therefore save the old state
  887. ; of the bit and then restore it later.  This keeps us from
  888. ; needing to DISABLE in flush.  It also fails miserably if someone
  889. ; does a start in the middle of a flush.
  890. ;
  891.  
  892. Flush:
  893.         PUTMSG  80,<'%s/Flush: called'>
  894.         movem.l d2/a6,-(sp)
  895.  
  896.         move.l  md_SysLib(a6),a6
  897.  
  898.         bset    #MDUB_STOPPED,UNIT_FLAGS(a4)
  899.         sne     d2
  900.  
  901. Flush_Loop:
  902.         move.l  a4,a0
  903.         CALLSYS GetMsg
  904.  
  905.         tst.l   d0
  906.         beq.s   Flush_End
  907.  
  908.         move.l  d0,a1
  909.         move.b  #IOERR_ABORTED,IO_ERROR(a1)
  910.         CALLSYS ReplyMsg
  911.  
  912.         bra.s   Flush_Loop
  913.  
  914. Flush_End:
  915.  
  916.         move.l  d2,d0
  917.         movem.l (sp)+,d2/a6
  918.  
  919.         tst.b   d0
  920.         beq.s   1$
  921.  
  922.         bsr     InternalStart
  923. 1$:
  924.  
  925.         move.l  a2,a1
  926.         bsr     TermIO
  927.  
  928.         rts
  929.  
  930. ;
  931. ; Foo and Bar are two device specific commands that are provided just
  932. ; to show you how to add your own commands.  The currently return that
  933. ; no work was done.
  934. ;
  935.  
  936. Foo:
  937. Bar:
  938.         CLEAR   d0
  939.         move.l  d0,IO_ACTUAL(a1)
  940.  
  941.         bsr     TermIO
  942.         rts
  943.  
  944. ;----------------------------------------------------------------------
  945. ;
  946. ; here begins the process related routines
  947. ;
  948. ; A Process is provided so that queued requests may be processed at
  949. ; a later time.
  950. ;
  951. ;
  952. ; Register Usage
  953. ; ==============
  954. ; a3 -- unit pointer
  955. ; a6 -- syslib pointer
  956. ; a5 -- device pointer
  957. ; a4 -- task (NOT process) pointer
  958. ; d7 -- wait mask
  959. ;
  960. ;----------------------------------------------------------------------
  961.  
  962. ; some dos magic.  A process is started at the first executable address
  963. ; after a segment list.  We hand craft a segment list here.  See the
  964. ; the DOS technical reference if you really need to know more about this.
  965.  
  966.         cnop    0,4                     ; long word allign
  967.         DC.L    16                      ; segment length -- any number will do
  968. myproc_seglist:
  969.         DC.L    0                       ; pointer to next segment
  970.  
  971. ; the next instruction after the segment list is the first executable address
  972.  
  973. Proc_Begin:
  974.  
  975.         move.l  _AbsExecBase,a6
  976.  
  977.         PUTMSG  80,<'Process started'>
  978.  
  979.         ;------ Grab the argument
  980.         move.l  4(sp),a5                ; Unit pointer
  981.  
  982.         move.l  md_Process(a5),a4       ; Point to device structure
  983.  
  984.         IFD     INTRRUPT
  985.         ;------ Allocate a signal for "I/O Complete" interrupts
  986.         moveq   #-1,d0                  ; -1 is any signal at all
  987.         CALLSYS AllocSignal
  988.         move.b  d0,mp_SigBit(A4)       ; Save in unit structure
  989.  
  990.         moveq   #0,d7                   ; Convert bit number signal mask
  991.         bset    d0,d7
  992.         move.l  d7,mp_SigMask(A4)      ; Save in unit structure
  993.  
  994.         lea.l   mp_is(a4),a1           ; Point to interrupt structure
  995.         moveq   #3,d0                   ; Portia interrupt bit 3
  996.         CALLSYS AddIntServer            ; Now install the server
  997.  
  998.         move.l  md_Base(a5),a0          ; Get board base address
  999.         bset.b  #INTENABLE,INTCTRL2(a0) ; Enable interrupts
  1000.         ENDC
  1001.  
  1002.         ;------ Allocate the right signal
  1003.  
  1004.         moveq   #-1,d0                  ; -1 is any signal at all
  1005.         CALLSYS AllocSignal
  1006.  
  1007.         move.b  d0,MP_SIGBIT(a4)
  1008.         move.b  #PA_SIGNAL,MP_FLAGS(a4)
  1009.  
  1010.         ;------ change the bit number into a mask, and save in d7
  1011.  
  1012.         moveq   #0,d7
  1013.         bset    d0,d7
  1014.  
  1015.         ;------
  1016.         ;------ OK, kids, we are done with initialization.  We now
  1017.         ;------ can start the main loop of the driver.  It goes
  1018.         ;------ like this.  Because we had the port marked PA_IGNORE
  1019.         ;------ for a while (in InitUnit) we jump to the getmsg
  1020.         ;------ code on entry.
  1021.         ;------
  1022.         ;------         wait for a message
  1023.         ;------         lock the device
  1024.         ;------         get a message.  if no message unlock device and loop
  1025.         ;------         dispatch the message
  1026.         ;------         loop back to get a message
  1027.         ;------
  1028.  
  1029.         bra.s   Proc_CheckStatus
  1030.  
  1031.         ;------ main loop: wait for a new message
  1032. Proc_MainLoop:
  1033.         PUTMSG  80,<'Process waiting'>
  1034.         move.l  d7,d0
  1035.         CALLSYS Wait
  1036.  
  1037. Proc_CheckStatus:
  1038.         ;------ see if we are stopped
  1039.         btst    #MDUB_STOPPED,UNIT_FLAGS(a4)
  1040.         bne.s   Proc_MainLoop           ; device is stopped
  1041.  
  1042.         ;------ lock the device
  1043.         bset    #UNITB_ACTIVE,UNIT_FLAGS(a4)
  1044.         bne.s   Proc_MainLoop           ; device in use
  1045.  
  1046.         ;------ get the next request
  1047. Proc_NextMessage:
  1048.         move.l  a4,a0
  1049.         CALLSYS GetMsg
  1050.         tst.l   d0
  1051.         beq.s   Proc_Unlock             ; no message?
  1052.  
  1053.         ;------ do this request
  1054.         move.l  d0,a1
  1055.         move.l  IO_UNIT(a1),a3
  1056.         exg     a5,a6                   ; put device ptr in right place
  1057.         bsr     PerformIO
  1058.         exg     a5,a6                   ; get syslib back in a6
  1059.  
  1060.         bra.s   Proc_NextMessage
  1061.  
  1062.         ;------ no more messages.  back ourselves out.
  1063. Proc_Unlock:
  1064.         and.b   #$ff&(~(UNITF_ACTIVE!UNITF_INTASK)),UNIT_FLAGS(a4)
  1065.         bra     Proc_MainLoop
  1066.  
  1067. ;
  1068. ; Here is a dummy interrupt handler, with some crucial components commented
  1069. ; out.  If the IFD INTRRUPT is enabled, this code will cause the device to
  1070. ; wait for a level two interrupt before it will process each request
  1071. ; (pressing a key on the keyboard will do it).  This code is normally
  1072. ; disabled, and must fake or omit certain operations since there  isn't
  1073. ; really any hardware for this driver.  Similiar code has been used
  1074. ; successfully in other, "REAL" device drivers.
  1075. ;
  1076.  
  1077.         IFD     INTRRUPT
  1078. ;       A1 should be pointing to the unit structure upon entry!
  1079.  
  1080. myintr:         move.l  mdu_Device(a1),a0       ; Get device pointer
  1081.                 move.l  md_SysLib(a0),a6        ; Get pointer to system
  1082.                 move.l  md_Base(a0),a0          ; point to board base address
  1083.                 btst.b  #IAMPULLING,INTCTRL1(a0);See if I'm interrupting
  1084.                 beq.s   myexnm                  ; if not set, exit, not mine
  1085.                 move.b  #0,INTACK(a0)           ; toggle controller's int2 bit
  1086.  
  1087. ;               ------ signal the task that an interrupt has occured
  1088.  
  1089.                 move.l  mdu_SigMask(a1),d0
  1090.                 lea     mdu_tcb(a1),a1
  1091.                 CALLSYS Signal
  1092.  
  1093. ;
  1094. ;               now clear the zero condition code so that
  1095. ;               the interrupt handler doesn't call the next
  1096. ;               interrupt server.
  1097. ;
  1098.                 moveq   #1,d0                   clear zero flag
  1099.                 bra.s   myexit                  now exit
  1100. ;
  1101. ;               this exit point sets the zero condition code
  1102. ;               so the interrupt handler will try the next server
  1103. ;               in the interrupt chain
  1104. ;
  1105. myexnm          moveq   #0,d0                   set zero condition code
  1106. ;
  1107. myexit          rts
  1108.         ENDC
  1109.  
  1110. mdu_Init:
  1111. ;       ------ Initialize the device
  1112.  
  1113.         INITBYTE        MP_FLAGS,PA_IGNORE
  1114.         INITBYTE        LN_TYPE,NT_DEVICE
  1115.         INITLONG        LN_NAME,myName
  1116.         INITBYTE        mp_Msg+LN_TYPE,NT_MSGPORT;Unit starts with MsgPort
  1117.         INITLONG        mp_Msg+LN_NAME,myName
  1118.         INITLONG        mp_tcb+LN_NAME,myName
  1119.         INITBYTE        mp_tcb+LN_TYPE,NT_TASK
  1120.         INITBYTE        mp_tcb+LN_PRI,5
  1121.         INITBYTE        mp_is+LN_PRI,4         ; Int priority 4
  1122.         IFD     INTRRUPT
  1123.         INITLONG        mp_is+IS_CODE,myintr   ; Interrupt routine addr
  1124.         ENDC
  1125.         INITLONG        mp_is+LN_NAME,myName
  1126.         DC.L    0
  1127.  
  1128. *mdn_Init:
  1129. *       ;------ Initialize packet for MakeDosNode
  1130.  
  1131.         INITLONG        mdn_execName,myName     ; Address of driver name
  1132.         INITLONG        mdn_tableSize,11        ; # long words in AmigaDOS env.
  1133.         INITLONG        mdn_dName,$52414d00     ; Store 'RAM' in name
  1134.         INITLONG        mdn_sizeBlock,128       ; # longwords in a block
  1135.         INITLONG        mdn_numHeads,1          ; RAM disk has only one "head"
  1136.         INITLONG        mdn_secsPerBlk,1        ; secs/logical block, must = "1"
  1137.         INITLONG        mdn_blkTrack,10         ; secs/track (must be reasonable)
  1138.         INITLONG        mdn_resBlks,1           ; reserved blocks, MUST > 0!
  1139.         INITLONG        mdn_upperCyl,615        ; upper cylinder
  1140.         INITLONG        mdn_numBuffers,1        ; # AmigaDOS buffers to start
  1141.         DC.L    0
  1142.  
  1143. ;HDDosNode:
  1144.                                   ;STRUCTURE MkDosNodePkt,0
  1145. ;        dc.l    DosDevName          ;APTR    mdn_dosName
  1146. ;        dc.l    myName              ;APTR    mdn_execName
  1147. ;        dc.l    1                   ;ULONG   mdn_unit
  1148. ;        dc.l    0                   ;ULONG   mdn_flags
  1149. ;        dc.l    12                  ;ULONG   mdn_tableSize
  1150. ;        dc.l    128                 ;ULONG   mdn_sizeBlock
  1151. ;        dc.l    0                   ;ULONG   mdn_secOrg
  1152. ;        dc.l    4                   ;ULONG   mdn_numHeads
  1153. ;        dc.l    1                   ;ULONG   mdn_secsPerBlk
  1154. ;        dc.l    17                  ;ULONG   mdn_blkTrack
  1155. ;        dc.l    2                   ;ULONG   mdn_resBlks
  1156. ;        dc.l    0                   ;ULONG   mdn_prefac
  1157. ;        dc.l    0                   ;ULONG   mdn_interleave
  1158. ;        dc.l    2                   ;ULONG   mdn_lowCyl
  1159. ;        dc.l    40                  ;ULONG   mdn_upperCyl
  1160. ;        dc.l    10                  ;ULONG   mdn_numBuffers
  1161. ;        dc.l    1                   ;ULONG   mdn_memBufType
  1162.                                     ;STRUCT  mdn_dName,5
  1163.                                     ;LABEL   mdn_Sizeof
  1164. *DosDevName:
  1165.         dc.b    'SFS',0
  1166.  
  1167. ;----------------------------------------------------------------------
  1168. ; EndCode is a marker that show the end of your code.
  1169. ; Make sure it does not span sections nor is before the
  1170. ; rom tag in memory!  It is ok to put it right after
  1171. ; the rom tag -- that way you are always safe.  I put
  1172. ; it here because it happens to be the "right" thing
  1173. ; to do, and I know that it is safe in this case.
  1174. ;----------------------------------------------------------------------
  1175. EndCode:
  1176.  
  1177.         END
  1178.